# coding=iso-8859-1
'''
Created on 21.9.2011

@author: mphkh
'''

from datetime import *

class Calendar(object):
    '''
    This class is a crude adaption from QuantLib calendar implementation.
    Implements Western Church calendar for determining Easter Monday.
    If Eastern Orthodox Church implementation is needed, a new class hierarchy could be constructed 
    such that Western and Eastern calendar inherits calendar and each country inherits subsequently.
    Non-business days are:
        Saturdays
        Sundays
    (only weekends implemented here)
    '''
    def isBusinessDay(self, ddate):
        '''
        Check if date is a business day
        Parameters: 
            ddate
        Returns:
            0 if date is a business day
            1 else
        '''
        if(self.isWeekend(ddate)):
            return 0
        else:
            return 1

    def followingBusinessDay(self, ddate):
        '''
        Determine following business day at date
        Parameters: 
            ddate
        Returns:
            business day following date
        '''
        ddate = ddate + timedelta(days=1)
        if self.isBusinessDay(ddate) == False:
            newdate = date + timedelta(days=1)
            return self.followingBusinessDay(newdate)
        else:
            return ddate
    
    def precedingBusinessDay(self, ddate):
        '''
        Determine preceding business day at date
        Parameters: 
            date
        Returns:
            business day preceding date
        '''
        ddate = ddate - timedelta(days=1)
        if self.isBusinessDay(ddate) == False:
            newdate = ddate + timedelta(days=-1)
            return self.precedingBusinessDay(newdate)
        else:
            return ddate
    
    def isEasterMonday(self, year):
        '''
        Determine at what day of the year Easter Monday is (January 1st is day 1) 
        Parameters: 
            year
        Returns:
            days (number of) since start of year when Easter Monday is
        '''
        return self.easterMonday(year)
    
    def isWeekend(self, ddate):
        '''
        Determine if date is on a weekend (Saturday or Sunday) 
        Parameters: 
            date
        Returns:
            1 if date is on a weekend
            0 else
            
        '''        
        # date.weekday() returns 0....6 where 0 is monday and 6 is sunday
        # weekday()>4 is either saturday or sunday
        if (ddate.weekday() > 4):
            return 1
        else:
            return 0
    
    def easterMonday(self, year):
        EasterMonday = [
                  98,  90, 103,  95, 114, 106,  91, 111, 102,   # 1901-1909
             87, 107,  99,  83, 103,  95, 115,  99,  91, 111,   # 1910-1919
             96,  87, 107,  92, 112, 103,  95, 108, 100,  91,   # 1920-1929
            111,  96,  88, 107,  92, 112, 104,  88, 108, 100,   # 1930-1939
             85, 104,  96, 116, 101,  92, 112,  97,  89, 108,   # 1940-1949
            100,  85, 105,  96, 109, 101,  93, 112,  97,  89,   # 1950-1959
            109,  93, 113, 105,  90, 109, 101,  86, 106,  97,   # 1960-1969
             89, 102,  94, 113, 105,  90, 110, 101,  86, 106,   # 1970-1979
             98, 110, 102,  94, 114,  98,  90, 110,  95,  86,   # 1980-1989
            106,  91, 111, 102,  94, 107,  99,  90, 103,  95,   # 1990-1999
            115, 106,  91, 111, 103,  87, 107,  99,  84, 103,   # 2000-2009
             95, 115, 100,  91, 111,  96,  88, 107,  92, 112,   # 2010-2019
            104,  95, 108, 100,  92, 111,  96,  88, 108,  92,   # 2020-2029
            112, 104,  89, 108, 100,  85, 105,  96, 116, 101,   # 2030-2039
             93, 112,  97,  89, 109, 100,  85, 105,  97, 109,   # 2040-2049
            101,  93, 113,  97,  89, 109,  94, 113, 105,  90,   # 2050-2059
            110, 101,  86, 106,  98,  89, 102,  94, 114, 105,   # 2060-2069
             90, 110, 102,  86, 106,  98, 111, 102,  94, 114,   # 2070-2079
             99,  90, 110,  95,  87, 106,  91, 111, 103,  94,   # 2080-2089
            107,  99,  91, 103,  95, 115, 107,  91, 111, 103,   # 2090-2099
             88, 108, 100,  85, 105,  96, 109, 101,  93, 112,   # 2100-2109
             97,  89, 109,  93, 113, 105,  90, 109, 101,  86,   # 2110-2119
            106,  97,  89, 102,  94, 113, 105,  90, 110, 101,   # 2120-2129
             86, 106,  98, 110, 102,  94, 114,  98,  90, 110,   # 2130-2139
             95,  86, 106,  91, 111, 102,  94, 107,  99,  90,   # 2140-2149
            103,  95, 115, 106,  91, 111, 103,  87, 107,  99,   # 2150-2159
             84, 103,  95, 115, 100,  91, 111,  96,  88, 107,   # 2160-2169
             92, 112, 104,  95, 108, 100,  92, 111,  96,  88,   # 2170-2179
            108,  92, 112, 104,  89, 108, 100,  85, 105,  96,   # 2180-2189
            116, 101,  93, 112,  97,  89, 109, 100,  85, 105    # 2190-2199
            ]
        return EasterMonday[year-1901];
